/**********************************************************************************************************************
 * @file    misc.h
 * @author  Queclink Hubert.Lee
 * @date    2016-10-27
 * @brief   Miscellaneous, 混杂的, 各种各样的定义以及函数.
 * @ingroup aadl
 *
 * Copyright (C) 2016 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 *
 * @usage
 * 1. unsigned short aad_crc16_modbus(const unsigned char *buf, unsigned int cnt)
 *   @brief  计算16位CRC校验值(CRC-16,0x8005,Modbus)
 *   @param  buf: [I],待计算数据;
 *           cnt: [I],待计算字节数.
 *   @retval 16位CRC校验值
 * 2. unsigned short aad_crc16_ccitt(const unsigned char *buf, unsigned int cnt)
 *   @brief  计算16位CRC校验值(CRC-CCITT(0xFFFF),0x1021)
 *   @param  buf: [I],待计算数据;
 *           cnt: [I],待计算字节数.
 *   @retval 16位CRC校验值
 * 3. bool aad_is_all_numeric(const char *buf, size_t cnt)
 *   @brief  判断多个字符是否全为数字
 *   @param  buf: [I],待判断字符;
 *           cnt: [I],待判断字符数.
 *   @retval true:全为数字, false:不全为数字.
 * 4. int aad_byte_to_chars(unsigned char byte, char *char1, char *char2)
 *   @brief  把字节转换为2字符, 如 0xA8=>'A''8', 0x7C=>'7''C'
 *   @param  byte: [I], 待转换字节;
 *           char1: [O], 转换到的第一个字符, 对应 byte 的高 4 位;
 *           char2: [O], 转换到的第二个字符, 对应 byte 的低 4 位;
 *   @retval 0:成功, others:错误码
 * 5. int aad_bytes_to_chars(unsigned char *bytes, size_t count, char *chars)
 *   @brief  把字节转换为字符, 如 0xA8,0x0D,0x3E=>'A''8''0''D''3''E'
 *   @param  bytes: [I], 待转换字节;
 *           count: [I], 待转换字节个数;
 *           chars: [O], 转换到的字符, 个数固定为 2*count;
 *   @retval 0:成功, others:错误码
 * 6. int aad_atoi(const char *str, size_t cnt)
 *   @brief  数组前cnt个数字转整形, 功能类似atoi
 *   @param  str: [I], 待转换数组;
 *           cnt: [I], 只转换数组的前cnt个数字;
 *   @retval 转换结果
 * 7. long int aad_strtol(const char *str, size_t cnt, int base)
 *   @brief  数组前cnt个数字转长整形, 功能类似strtol
 *   @param  str: [I], 待转换数组;
 *           cnt: [I], 只转换数组的前cnt个数字;
 *           base: [I], 进制, 如10,16.
 *   @retval 转换结果
 * 8. unsigned int aad_list_node_count(struct list_head *head)
 *   @brief  计算链表中有效节点数目
 *   @param  head: [I], 待计算链表头指针;
 *   @retval 链表中有效节点数目
 * 9. const char *aad_lf_field_search(const char *str, int index, size_t *size)
 *   @brief  从字符串中以换行符(Line Feed, \r\n or \n)为分隔符查找对应的字段
 *   @param  str: [I], 待查找字符串;
 *           index: [I], 待查找字段号, 从0开始;
 *           size: [O], 查找到的字段长度, 仅当函数返回非空时有效;
 *   @retval 查找到的字段起始指针, NULL:未找到字段
 * 10. const char *aad_comma_field_search(const char *str, int index, size_t *size)
 *   @brief  从字符串中以','为分隔符查找对应的字段
 *   @note   1)从第1个','起作为有效数据;
 *           2)自动跳过找到的字段前面的空格;
 *   @param  str: [I], 待查找字符串;
 *           index: [I], 待查找字段号, 从0开始;
 *           size: [O], 查找到的字段长度, 仅当函数返回非空时有效;
 *   @retval 查找到的字段起始指针, NULL:未找到字段, 或字段为空, (不表示没有下一个字段)
 * 11. const char *aad_at_field_search(const char *str, int index, size_t *size)
 *   @brief  从字符串(一般为AT指令)中以':'为起始字符, 以','为分隔符查找对应的字段
 *   @note   自动跳过找到的字段前面的空格;'\r''\n'也作为分隔符使用.
 *   @param  str: [I], 待查找字符串;
 *           index: [I], 待查找字段号, 从0开始;
 *           size: [O], 查找到的字段长度, 仅当函数返回非空时有效;
 *   @retval 查找到的字段起始指针, NULL:未找到字段, 或字段为空, (不表示没有下一个字段)
 * 12. const char *aad_at_strtok(const char *str, size_t *size)
 *   @brief  从字符串(一般为AT指令)中以':'为起始字符, 以','为分隔符逐个查找字段
 *   @note   1.固定以':'为起始字符, 以','为分隔符;
 *           2.自动跳过找到的字段前面的空格;
 *           3.函数使用方法类似strtok, 但不会对str作任何修改;
 *           4.函数不可重入, 在OS环境中, 用户务必自行做好保护;
 *   @param  str: [I], 待查找字符串, 查找首字段时不可为空, 查找下一个字段时必须为空(NULL);
 *           size: [O], 查找到的字段长度, 仅当函数返回非空时有效;
 *   @retval 查找到的字段起始指针, NULL:未找到字段, 或字段为空, (不表示没有下一个字段)
 * 13. int aad_at_field_count(const char *str)
 *   @brief  从字符串(一般为AT指令)中以':'为起始字符, 以','为分隔符计算字段数目
 *   @note   包括空字段(如"XX:,,X,"有4个字段)
 *   @param  str: [I], 待查找字符串;
 *   @retval 非负数:字段数目, others:错误码
 * 14. char *aad_memstr(const void *buf, size_t n, const char *str)
 *   @brief  从缓存区中查找字符串(不包括'\0'), 查找到第1个字符串返回.
 *   @param  buf: [I], 缓存区;
 *           n: [I], 缓存区长度;
 *           str: [I], 待查找字符串;
 *   @retval NULL:未找到, others:找到字符串str,返回其在缓存区中的首地址.
 * 15. char *aad_memstr_last(const void *buf, size_t n, const char *str)
 *   @brief  从缓存区中查找字符串(不包括'\0'), 查找到最后1个字符串返回.
 *   @param  buf: [I], 缓存区;
 *           n: [I], 缓存区长度;
 *           str: [I], 待查找字符串;
 *   @retval NULL:未找到, others:找到字符串str,返回其在缓存区中的首地址.
 * 16. int aad_difftime(time_t new, time_t last)
 *   @brief  计算时间差(new-last)
 *   @param  new: [I], 新的时间;
 *           last: [I], 之前的时间.
 *   @retval 时间差, 单位s, 正数表示new比last晚, 负数表示new比last早.
 * 17. int aad_strrepl(char *str, const char *victim, const char c)
 *   @brief  替换字符串中的字符(把字符串str中的victim全替换为c)
 *   @param  str: [IO], 待处理的字符串;
 *           victim: [I], 需要被替换的字符, 字符串格式;
 *           c: [I], 替换成该字符.
 *   @note   str="a b,c", victim=" ,", c='_', 执行函数后str="a_b_c".
 *   @retval 0:成功, others:错误码.
 * 18. int aad_strtrim(char *str, const char *trim)
 *   @brief  修剪字符串(去掉字符串str前后的trim字符)
 *   @param  str: [IO], 待修剪的字符串;
 *           trim: [I], 前后需要去掉的字符, 字符串格式.
 *   @note   str=", a b,c,", c=" ,", 执行函数后str="a b,c".
 *   @retval 0:成功, others:错误码.
 * 19. unsigned int aad_char_amount(const char *buf, size_t cnt, const char c)
 *   @brief  计算缓存区中包含的某字符的个数(buf中有几个c)
 *   @param  buf: [I], 缓存区;
 *           cnt: [I], 缓存区长度;
 *           c: [I], 待统计的字符.
 *   @retval 字符个数.
 * 20. int aad_basename(const char *path, char *basename)
 *   @brief  获取文件名函数
 *   @param  path: [I], 完整路径, 字符串;
 *           basename: [O], 文件名, 字符串.
 *   @note   函数功能与basename一致.
 *   @retval 0:成功, others:错误码.
 * 21. int aad_dirname(const char *path, char *dirname)
 *   @brief  获取目录名函数
 *   @param  path: [I], 完整路径, 字符串;
 *           dirname: [O], 目录名, 字符串.
 *   @note   函数功能与dirname一致.
 *   @retval 0:成功, others:错误码.
 * 22. int aad_avg_int(const int *buf, size_t cnt)
 *   @brief  求平均值(int)
 *   @param  buf: [I], 原始数据;
 *           cnt: [I], 原始数据个数.
 *   @retval 平均值.
 * 23. unsigned int aad_avg_uint(const unsigned int *buf, size_t cnt)
 *   @brief  求平均值(unsigned int)
 *   @param  buf: [I], 原始数据;
 *           cnt: [I], 原始数据个数.
 *   @retval 平均值.
 * 24. char *aad_field_search_pre(const char *start, const char *end, size_t *size)
 *   @brief  从 end 往 start 方向查找字段, 遇到空白字符(isspace)终止.
 *   @note   如"abcd efg \r\nhijk", start->a,end->\n,则找到"efg",start->a,end->k,则找到"hijk".
 *   @param  start: [I], 缓存区起始处;
 *           end: [I], 缓存区结束处;
 *           size: [O], 找到的字段长度.
 *   @retval NULL:未找到, others:找到的字段的首地址.
 * 25. char *aad_field_search_post(const char *start, const char *end, size_t *size)
 *   @brief  从 start 往 end 方向查找字段, 遇到空白字符(isspace)终止.
 *   @note   如"abcd\t efg \r\nhijk", start->a,end->\n,则找到"abcd",start->\t,end->k,则找到"efg".
 *   @param  start: [I], 缓存区起始处;
 *           end: [I], 缓存区结束处;
 *           size: [O], 找到的字段长度.
 *   @retval NULL:未找到, others:找到的字段的首地址.
 *
 * 26. void base64_encode(const char *buf, const unsigned int size, char *base64_char)
 *   @brief  base64编码函数.
 *   @param  *buf: [I], 要进行编码的字符串起始地址;
 *           size: [I], 要进行编码的字符串长度;
 *           *base64_char: [O], 编码后输出的存储地址.
 *   @retval None.
 *
 *********************************************************************************************************************/


#ifndef __AADL_MISC_H
#define __AADL_MISC_H

/* includes ---------------------------------------------------------------------------------------------------------*/
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif



unsigned short aad_crc16_modbus(const unsigned char *buf, unsigned int cnt);
unsigned short aad_crc16_ccitt(const unsigned char *buf, unsigned int cnt);

bool aad_is_all_numeric(const char *buf, size_t cnt);
unsigned int aad_char_amount(const char *buf, size_t cnt, const char c);

int aad_byte_to_chars(unsigned char byte, char *char1, char *char2);
int aad_bytes_to_chars(unsigned char *bytes, size_t count, char *chars);


const char *aad_lf_field_search(const char *str, int index, size_t *size);
const char *aad_comma_field_search(const char *str, int index, size_t *size);
const char *aad_at_field_search(const char *str, int index, size_t *size);
int aad_at_field_count(const char *str);
const char *aad_at_strtok(const char *str, size_t *size);
char *aad_field_search_pre(const char *start, const char *end, size_t *size);
char *aad_field_search_post(const char *start, const char *end, size_t *size);
const char *skip_front_cmdchar(const char *str);
char *aad_memstr_check_end(const void *buf, size_t n, const char *key, const char *end);

int aad_atoi(const char *str, size_t cnt);
char *aad_memstr(const void *buf, size_t n, const char *str);
char *aad_memstr_last(const void *buf, size_t n, const char *str);
int aad_difftime(time_t new, time_t last);
long int aad_strtol(const char *str, size_t cnt, int base);
int aad_strrepl(char *str, const char *victim, const char c);
int aad_strtrim(char *str, const char *trim);

int aad_avg_int(const int *buf, size_t cnt);
unsigned int aad_avg_uint(const unsigned int *buf, size_t cnt);

int aad_basename(const char *path, char *basename);
int aad_dirname(const char *path, char *dirname);

void base64_encode(const char *buf, const unsigned int size, char *base64_char);


#ifdef __cplusplus
}
#endif

#endif /* __AADL_MISC_H */
